#include "ScalingWorker.h"
#include "Data.h"
#include "StorageInterface.h"
#include "CMSInterface.h"

bool ScalingWorker::ChkSettings()
{
	if(Settings::ApplyChangedSettingValue())
	{
		LOG::SendSMS("server setting has been changed");


		printf("\n#################### Changed Setting Values ################\n");
		printf("%s" , Settings::GetSettings()->dump().c_str());
		printf("###############################################################\n");
		

		if('K' == Settings::GetSettings()->OPERATION_MODE || 'k' == Settings::GetSettings()->OPERATION_MODE)
			return false;

	}

	return true;
}


int ScalingWorker::CalcInstanceCount(const int waiting_count)
{

	const int block_size = Settings::GetSettings()->AGENT_BLOCK_SIZE;

	const int rendering_count_per_check = Settings::GetSettings()->RENDERING_PER_MIN * Settings::GetSettings()->SCALE_UP_INTERVAL * block_size;

	int block_count  = 1 + waiting_count / rendering_count_per_check;

	const int cond = rendering_count_per_check *  Settings::GetSettings()->BLOCK_CALC_RATIO;
	if( waiting_count % rendering_count_per_check >= cond)
		block_count += 1;
	
	return	block_count * block_size;
}

void ScalingWorker::DoWork()
{


	if(!StorageInterface::LaunchDefaultAgents())
		return;

	int setting_count = 0;

	time_t stop_check_time = time(NULL);

	time_t start_scale_up_time = time(NULL);

	int scale_count = 0;
	int sum_waiting_count = 0;
	time_t start_scale_down_time = time(NULL);
	time_t sms_tick_time = time(NULL);

	time_t default_check_time = time(NULL);

	while(!bStop)
	{
		sleep(Settings::GetSettings()->JOB_CHECK_DELAY);

		if(!Settings::GetSettings()->IsControllerAddr())
		{
			printf("[scaler] Invalid scaler for this zone\n");
			LOG::PushProcessLog(_ERROR , "Invalid scaler for this zone");
			break;
		}

		if(time(NULL) - sms_tick_time > Settings::GetSettings()->PUSH_ALIVE_TICK_DELAY * 60)
		{
			LOG::SendSMS("ALIVE!!");
			sms_tick_time = time(NULL);
		}


		if(++setting_count >= Settings::GetSettings()->SETTING_CHECK_COUNT)
		{
			setting_count = 0;
			if(!ChkSettings())
				break;
		}

		if(time(NULL) - stop_check_time >= 30)
		{
			StorageInterface::StopEC2();

			stop_check_time = time(NULL);
		}

		if(time(NULL) - default_check_time >= 150) 
		{
			StorageInterface::LaunchDefaultAgents();
			default_check_time = time(NULL);
		}

		if((time(NULL) - start_scale_up_time) / 60 >= Settings::GetSettings()->SCALE_UP_INTERVAL)
		{
			const int waiting_job_count = CMSInterface::GetWaitingJobCount();
			printf("waiting count : %d\n" , waiting_job_count);

			if(waiting_job_count < 0)
				continue;

			const int needed_instance_count = CalcInstanceCount(waiting_job_count);

			const int running_instance_count = StorageInterface::GetRunningInstanceCount();
			if(running_instance_count < 0)
				continue;

			int change_instance_count = needed_instance_count - running_instance_count;

			if(change_instance_count == 0)
			{
				printf("NO INSTANCE CHANGE : %d\n" , needed_instance_count);

				scale_count = 0;
				sum_waiting_count = 0;
				start_scale_down_time = time(NULL);
			}
			else if(change_instance_count > 0)
			{
				int reg_instance_count;
				_DB_RESULT db_result = DBInterface::GetRegInstanceCount(Settings::GetSettings()->RENDERER_ID , reg_instance_count);
				if(_DB_SUCCESS != db_result)
				{
					char buf[1024];
					sprintf(buf , "DB::GetRegInstanceCount  :%d " ,db_result);
					printf("%s\n" , buf);
					LOG::PushProcessLog(_ERROR, buf);
					reg_instance_count = Settings::GetSettings()->MAX_AGENT;
				}

				if( needed_instance_count > reg_instance_count )
				{
					change_instance_count = reg_instance_count - running_instance_count;
					if(change_instance_count < 0)
						change_instance_count = 0;
				}

				printf("INC INSTANCE :waiting(%d) [running(%d) ,  start(%d) =  total(%d)]\n" 
					,waiting_job_count , running_instance_count , change_instance_count , running_instance_count + change_instance_count);

				if(!StorageInterface::StartEC2(change_instance_count))
					continue;

				LOG::PushScalingLog(_REQUIRED , waiting_job_count , change_instance_count , running_instance_count + change_instance_count);

				scale_count = 0;
				sum_waiting_count = 0;
				start_scale_down_time = time(NULL);

			}
			else
			{
				scale_count ++;
				sum_waiting_count += waiting_job_count;
			}

			start_scale_up_time = time(NULL);

		} 


		if( (time(NULL) - start_scale_down_time) / 60 >= Settings::GetSettings()->SCALE_DOWN_INTERVAL)
		{
			if(scale_count > 0)
			{
				const int avg_waiting_count = MATH::round((double)sum_waiting_count / (double)scale_count);
				const int needed_instance_count = CalcInstanceCount(avg_waiting_count);
				const int running_instance_count = StorageInterface::GetRunningInstanceCount();
				if(running_instance_count < 0)
					continue;

				int change_instance_count = needed_instance_count - running_instance_count;

				if(change_instance_count < 0)
				{
					change_instance_count = -1 * Settings::GetSettings()->AGENT_BLOCK_SIZE;

					int default_instance_count = 0;
					_DB_RESULT db_result = DBInterface::GetRegInstanceCount(Settings::GetSettings()->RENDERER_ID , default_instance_count , true);
					if(_DB_SUCCESS != db_result)
					{
						char buf[1024];
						sprintf(buf , "DB::GetRegInstanceCount(always)  :%d " ,db_result);
						printf("%s\n" , buf);
						LOG::PushProcessLog(_ERROR, buf);

						change_instance_count = 0;
					}
					else
					{
						if(default_instance_count < Settings::GetSettings()->AGENT_BLOCK_SIZE)
						{
							default_instance_count = Settings::GetSettings()->AGENT_BLOCK_SIZE;
						}

						if(running_instance_count + change_instance_count < default_instance_count)
						{
							change_instance_count = -(running_instance_count - default_instance_count);
							if(change_instance_count > 0)
								change_instance_count = 0;
						}
					}

					printf("DEC INSTANCE :avg waiting(%d) [running(%d) , stop(%d) = total(%d)]\n" 
						,avg_waiting_count , running_instance_count , change_instance_count , running_instance_count + change_instance_count);

					if(!StorageInterface::StopAgent(60 - Settings::GetSettings()->SCALE_UP_INTERVAL , abs(change_instance_count)))
						continue;

					LOG::PushScalingLog( _REQUIRED  , avg_waiting_count , change_instance_count , running_instance_count + change_instance_count);

				}
			} 

			scale_count = 0;
			sum_waiting_count = 0;
			start_scale_down_time = time(NULL);

		}


	} 
}